package javbot.script;

import java.awt.AWTException;
import java.awt.Point;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javbot.command.CmdClick;
import javbot.command.CmdEvent;
import javbot.command.CmdExecute;
import javbot.command.CmdGoTo;
import javbot.command.CmdJumpTo;
import javbot.command.CmdMailFiles;
import javbot.command.CmdPressKey;
import javbot.command.CmdScreenshot;
import javbot.command.CmdType;
import javbot.command.CmdWait;
import javbot.command.Command;

public class ScriptParser {
	
	public static Command[] parseScript(String script){
				
		try {
			ArrayList<Command> co = (new ScriptStateParser(script)).parseScript();
			return co.toArray(new Command[co.size()]);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return new Command[0];
		
	}

	public static Command parseCommand(String line) throws AWTException {

		Command command = null;
		line = line.trim();
		String line_lc = line.toLowerCase();
		if (line_lc.startsWith("!")) {
			if (line_lc.startsWith("!k")) {
				if (line_lc.startsWith("!kp")) {
					line = line.substring(3).trim();
					int code = Integer.parseInt(line);
					command = new CmdEvent(CmdEvent.KEY_PRESS, code);
				} else if (line_lc.startsWith("!kr")) {
					line = line.substring(3).trim();
					int code = Integer.parseInt(line);
					command = new CmdEvent(CmdEvent.KEY_RELEASE, code);
				}
			} else if (line_lc.startsWith("!m")) {
				int code = 101;

				if (line_lc.charAt(2) == 'r')
					code++;
				switch (line_lc.charAt(3)) {
				case 'm':
					code += 2;
					break;
				case 'r':
					code += 4;
					break;
				}

				command = new CmdEvent(code);
			}
		} else if (line_lc.startsWith("jump to")) {
			Point point = getPointFromString(line_lc);
			command = new CmdJumpTo(point.x, point.y);
		} else if (line_lc.startsWith("go to")) {
			Point point = getPointFromString(line_lc);
			command = new CmdGoTo(point.x, point.y);
		} else if (line_lc.startsWith("click")) {
			line_lc = line_lc.substring(5).trim();
			int times = 1;
			if (line_lc.length() > 0) {
				if (line_lc.equals("twice"))
					times = 2;
				else {
					times = Integer.parseInt(line_lc);
				}
			}
			command = new CmdClick(times);
		} else if (line_lc.startsWith("key")) {
			command = new CmdPressKey(line.substring(3));
		} else if (line_lc.startsWith("wait")) {
			line = line.substring(4).trim();
			int seconds = Integer.parseInt(line);
			command = new CmdWait(seconds);
		} else if (line_lc.startsWith("type")) {
			line = line.substring(4).trim();
			if (line.startsWith("'") && line.endsWith("'"))
				line = line.substring(1, line.length() - 1);
			command = new CmdType(line, 5);
		} else if (line_lc.startsWith("screenshot")) {
			line_lc = line_lc.substring(10).trim();
			Pattern pattern1 = Pattern.compile("q(\\d{1,3})\\ss(\\d{1,4})");
			Pattern pattern2 = Pattern.compile("q(\\d{1,3})");
			Pattern pattern3 = Pattern.compile("s(\\d{1,4})");
			Matcher matcher1 = pattern1.matcher(line_lc);			
			Matcher matcher2 = pattern2.matcher(line_lc);
			Matcher matcher3 = pattern3.matcher(line_lc);
			if (matcher1.matches()) {
				command = new CmdScreenshot(
						Integer.parseInt(matcher1.group(1)),
						Integer.parseInt(matcher1.group(2)));
			} else if (matcher2.matches()) {
				command = new CmdScreenshot(
						Integer.parseInt(matcher2.group(1)),
						100);
			} else if (matcher3.matches()) {
				command = new CmdScreenshot(
						100,
						Integer.parseInt(matcher3.group(1)));
			}
			else
				command = new CmdScreenshot();
		} else if (line_lc.startsWith("mail files")) {
			line = line.substring(10).trim();
			command = new CmdMailFiles(line);
		} else if (line_lc.startsWith("execute")) {
			line = line.substring(8).trim();
	        Pattern p2 = Pattern.compile("'(.*)'(.*)");
	        Matcher m2 = p2.matcher(line);
	        if (m2.matches()) {
	        	if (m2.group(2).contains(">>")) {
	        		String file = m2.group(2).trim().substring(2).trim();
	        		command = new CmdExecute(
	        				m2.group(1).trim(),
	        				file
	        				);
	        		
	        	} else {
	        		command = new CmdExecute(m2.group(1).trim());
	        	}
	        	
	        	
	        }
			
//			if (line.startsWith("'") && line.endsWith("'"))
//				line = line.substring(1, line.length() - 1);
//			command = new CmdExecute(line);
		}
		return command;
	}

	private static Point getPointFromString(String line) {
		line = line.substring(line.indexOf('(') + 1, line.indexOf(')'));
		int x = Integer.parseInt(line.substring(0, line.indexOf(',')).trim());
		int y = Integer.parseInt(line.substring(line.indexOf(',') + 1).trim());
		Point point = new Point(x, y);
		return point;
	}
}

class ScriptStateParser {

	private final char[] scriptChars;

	private final static int STATE_NORMAL = 1;

	private final static int STATE_IN_QUOTES = 2;

	private final static int STATE_IN_COMMENTS = 3;

	private int state = 1;

	private StringBuffer tmpLine = new StringBuffer();

	private ArrayList<Command> commands = new ArrayList<Command>();

	ScriptStateParser(String script) {
		this.scriptChars = script.toCharArray();
	}

	protected ArrayList<Command> parseScript() throws AWTException {

		for (int i = 0; i < scriptChars.length; i++) {
			switch (state) {
			case STATE_NORMAL:

				if (scriptChars[i] == '\'') {
					tmpLine.append('\'');
					state = STATE_IN_QUOTES;
				} else if (scriptChars[i] == '#') {
					state = STATE_IN_COMMENTS;
				} else if (scriptChars[i] == ';') {
					addCommand();
				} else {
					tmpLine.append(scriptChars[i]);
				}
				break;

			case STATE_IN_QUOTES:

				if (scriptChars[i] == '\'') {
					tmpLine.append('\'');
					state = STATE_NORMAL;
				} else {
					tmpLine.append(scriptChars[i]);
				}
				break;

			case STATE_IN_COMMENTS:

				if (scriptChars[i] == '\n') {
					state = STATE_NORMAL;
				}
				break;
			}
		}

		return commands;
	}

	private void addCommand() throws AWTException {
		String line = tmpLine.toString().trim();
		if (line.length() > 0) {
			Command c = ScriptParser.parseCommand(line);
			if (c != null)
				commands.add(c);
		}
		
		
		tmpLine = new StringBuffer();
	}

}